package com.ruiyi.adrobot.web.controller.robot;

import com.alibaba.fastjson.JSONObject;
import com.ruiyi.adrobot.beans.Area;
import com.ruiyi.adrobot.beans.*;
import com.ruiyi.adrobot.beans.common.MongoPageRequest;
import com.ruiyi.adrobot.beans.common.ResultMsg;
import com.ruiyi.adrobot.beans.socket.SocketRequest;
import com.ruiyi.adrobot.mongo.device.DeviceRepository;
import com.ruiyi.adrobot.mongo.fun.FunRepository;
import com.ruiyi.adrobot.mongo.model.ModelRepository;
import com.ruiyi.adrobot.mongo.robot.RobotRepository;
import com.ruiyi.adrobot.mongo.taskdetail.TaskDetailRepository;
import com.ruiyi.adrobot.mongo.wifi.WifiRepository;
import com.ruiyi.adrobot.service.vpn.VpnService;
import com.ruiyi.adrobot.utils.DateUtil;

import com.ruiyi.adrobot.utils.RandomUtil;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;

/**
 * Created by Lenovo on 2017/5/8.
 */
@Controller
@RequestMapping("/robot")
public class RobotController {
    @Autowired
    private RobotRepository robotRepository;
    @Autowired
    private TaskDetailRepository taskDetailRepository;
    @Autowired
    private ModelRepository modelRepository;
    @Autowired
    private DeviceRepository deviceRepository;
    @Autowired
    private WifiRepository wifiRepository;
    @Resource(name = "redisTemplate")
    private ValueOperations<String, Integer> redisOperations;
    @Autowired
    private VpnService vpnService;
    @Autowired
    private FunRepository funRepository;

    @RequestMapping(value = "/conf", method = RequestMethod.POST)
    @ResponseBody
    public ResultMsg<Map<String, Object>> conf(@RequestBody TaskConfig taskConfig) {
        String createDate = DateUtil.getCurrentTime();
        String taskNo = createDate.replace("-", "").replace(" ", "").replace(":", "");
        for (int i = 0; i < taskConfig.getCycleNumber(); i++) {
            List<TaskDetail.Task> tasks = new LinkedList<>();
            // 计算出各个流程分配数量
            Integer allotTime = 0;
            for (TaskConfig.Flow flow : taskConfig.getFlows()) {
                Fun.Flow.Action action = funRepository.findActionByFunAndFlowsId(taskConfig.getFun(), flow.getId());
                flow.setAction(action);
                for (int j = 0; j < flow.getTime(); j++) {
                    String startTimeStr = DateUtil.getDateStringByTime(DateUtil.getTimeByString(taskConfig.getStartTime()) + RandomUtil.nextLong(DateUtil.getTimeByString(taskConfig.getEndTime()) - DateUtil.getTimeByString(taskConfig.getStartTime())));
                    TaskDetail.Task task = new TaskDetail.Task(flow.getId(), allotTime++, startTimeStr);
                    // 判断是否选择有账户的设备信息
                    Integer index = checkHaveStepType3(action);
                    if (index >= 0) {
                        task.setStepType3(index);
                    }
                    tasks.add(task);
                }
            }
            Collections.sort(tasks); // 通过开始时间排序
            TaskDetail taskDetail = new TaskDetail(taskNo + "_" + i, taskConfig.getFun(), taskConfig.getGroupNames(), allotTime, DateUtil.addDate(taskConfig.getStartTime(), i), DateUtil.addDate(taskConfig.getEndTime(), i), tasks,
                    false, taskConfig.getFlows(), createDate, taskConfig.getDidType(), taskConfig.getDeviceType());
            taskDetailRepository.insert(taskDetail);
        }
        return ResultMsg.success();
    }

    @RequestMapping(value = "/releaseAll", method = RequestMethod.GET)
    @ResponseBody
    public ResultMsg<Map<String, Object>> releaseAll() {
        releaseAllIp();
        JSONObject jsonObject;
        do {
            jsonObject = vpnService.switchIp(Area.ALL, null);
        } while (jsonObject.getInteger("status") == 0);
        redisOperations.set("vpnOnline", jsonObject.getInteger("online"));
        releaseAllIp();
        return ResultMsg.success();
    }

    private void releaseAllIp() {
        JSONObject jsonObject = vpnService.getOnlineInfo();
        for (Object object : jsonObject.getJSONArray("list")) {
            vpnService.releaseIp(((JSONObject) object).getString("ip"));
        }
    }

    @RequestMapping(value = "/group/findAll/{online}", method = RequestMethod.GET)
    @ResponseBody
    public List<Group> findAll(@PathVariable("online") Boolean online) {
        return robotRepository.findGroups(online);
    }

    @RequestMapping(value = "/toRobotList", method = RequestMethod.GET)
    public String toRobotList() {
        return "robot/list";
    }

    @RequestMapping(value = "/getListByPage", method = RequestMethod.GET)
    @ResponseBody
    public Page<Robot> getRobotListByPage(MongoPageRequest<Robot> mongoPageRequest, Robot robot) {
        mongoPageRequest.setParams(robot);
        return robotRepository.getListByPage(mongoPageRequest);
    }

    private Integer checkHaveStepType3(Fun.Flow.Action action) {
        if (null != action.getSteps()) {
            for (int i = 0; i < action.getSteps().size(); i++) {
                if (action.getSteps().get(i).getStepType() == 3) {
                    return i;
                }
            }
        }
        return -1;
    }

    @RequestMapping(value = "/toconf", method = RequestMethod.GET)
    public String toConf() {
        return "robot/conf";
    }


    @RequestMapping(value = "/stop", method = RequestMethod.GET)
    @ResponseBody
    public ResultMsg<Map<String, Object>> stop() {
        List<ChannelHandlerContext> list = NettyChannelhandlerContextMap.getChannelHandlerContextList();
        Iterator<ChannelHandlerContext> it = list.iterator();
        while (it.hasNext()) {
            SocketRequest socketRequest = new SocketRequest("stop_fun", null);
            it.next().writeAndFlush(socketRequest.toString());
        }
        return ResultMsg.success();
    }

    @RequestMapping(value = "/updateGroupName", method = RequestMethod.GET)
    @ResponseBody
    public ResultMsg<Map<String, Object>> updateGroupName(@RequestParam("simCode") String simCode, @RequestParam("oldGroupName") String oldGroupName, @RequestParam("newGroupName") String newGroupName) {
        if (oldGroupName.equals(newGroupName)) {
            return ResultMsg.error("新的组名不能和当前组名相同");
        }
        Robot robot = robotRepository.findBySimCode(simCode);
        robot.setGroupName(newGroupName);
        robotRepository.save(robot);
        return ResultMsg.success();
    }

    @RequestMapping(value = "/updateNickName", method = RequestMethod.GET)
    @ResponseBody
    public ResultMsg<Map<String, Object>> updateNickName(@RequestParam("simCode") String simCode, @RequestParam("nickName") String nickName) {
        Robot robot = robotRepository.findBySimCode(simCode);
        Long count = robotRepository.countByGroupNameAndNickName(robot.getGroupName(), nickName);
        if (count > 0) {
            return ResultMsg.error("该组已存在相同的别名");
        }
        robot.setNickName(nickName);
        robotRepository.save(robot);
        return ResultMsg.success();
    }

    @RequestMapping(value = "/updateByParamType", method = RequestMethod.GET)
    @ResponseBody
    public ResultMsg<Map<String, Object>> updateModel(@RequestParam("simCode") String simCode, @RequestParam("param") String param, @RequestParam("type") Integer type) {
        Robot robot = robotRepository.findBySimCodeAndOnlineAndBusy(simCode, true, false);
        if (null == robot) {
            return ResultMsg.error("设备不在线或处于忙碌状态，不能修改");
        }
        switch (type) {
            case 0:
                robot.setBrand(param);
                break;
            case 1:
                robot.setModel(param);
                break;
            case 2:
                robot.setDisplayId(param);
                break;
            case 3:
                robot.setVersionAndroid(param);
                break;
            case 4:
                robot.setBoard(param);
                break;
        }
        SocketRequest socketRequest = new SocketRequest("update_model", Model.class);
        socketRequest.setParams(new Model(robot.getBrand(), robot.getModel(), robot.getDisplayId(), robot.getVersionAndroid(), robot.getBoard(), robot.getOsApi()));
        ChannelHandlerContext ctx = NettyChannelhandlerContextMap.get(robot.getSimCode());
        if (null != ctx) {
            ctx.writeAndFlush(socketRequest.toString());
        } else {
            return ResultMsg.error("当前设备不在线，不能修改");
        }
        robotRepository.save(robot);
        return ResultMsg.success();
    }

    @RequestMapping(value = "/changeModel", method = RequestMethod.GET)
    @ResponseBody
    public ResultMsg<Map<String, Object>> changeModel() {
        List<Robot> robots = robotRepository.findByOnlineAndBusy(true, false);
        Iterator<Robot> it = robots.iterator();
        while (it.hasNext()) {
            Robot robot = it.next();
            Model model = modelRepository.findByModel(deviceRepository.findRandomModel().getModel());
            SocketRequest socketRequest = new SocketRequest("update_model", Model.class);
            socketRequest.setParams(model);
            ChannelHandlerContext ctx = NettyChannelhandlerContextMap.get(robot.getSimCode());
            if (null != ctx) {
                ctx.writeAndFlush(socketRequest.toString());
            }
            robot.setBrand(model.getBrand());
            robot.setModel(model.getModel());
            robot.setDisplayId(model.getDisplayId());
            robot.setVersionAndroid(model.getVersionAndroid());
            robot.setBoard(model.getBoard());
            robotRepository.save(robot);
        }
        return ResultMsg.success();
    }

    @RequestMapping(value = "/toUpdateModel", method = RequestMethod.GET)
    public String toUpdateModel(String simCode, ModelMap modelMap) {
        modelMap.put("simCode", simCode);
        return "robot/update_model";
    }

    @RequestMapping(value = "/model/getListByPage", method = RequestMethod.GET)
    @ResponseBody
    public Page<Model> getModelAll(MongoPageRequest<Model> mongoPageRequest, Model model) {
        mongoPageRequest.setParams(model);
        return modelRepository.getListByPage(mongoPageRequest);
    }

    @PostMapping("/update")
    @ResponseBody
    public ResultMsg update(Robot robot) {
        Robot oldRobot = robotRepository.findBySimCode(robot.getSimCode());
        // 修改设备信息
        if (null != robot.getBrand()) {
            if (updateModel(robot, oldRobot)) return ResultMsg.error("当前设备不在线，不能修改");
            oldRobot.setBrand(robot.getBrand());
            oldRobot.setModel(robot.getModel());
            oldRobot.setDisplayId(robot.getDisplayId());
            oldRobot.setVersionAndroid(robot.getVersionAndroid());
            oldRobot.setBoard(robot.getBoard());
        }
        // 修改Wifi
        if (null != robot.getWifi()) {
            oldRobot.setWifi(robot.getWifi());
            ChannelHandlerContext ctx = NettyChannelhandlerContextMap.get(oldRobot.getSimCode());
            SocketRequest<Wifi> socketRequest = new SocketRequest<>("update_wifi", robot.getWifi());
            ctx.writeAndFlush(socketRequest.toString());
        }
        robotRepository.save(oldRobot);
        return ResultMsg.success();
    }

    private boolean updateModel(Robot robot, Robot oldRobot) {
        SocketRequest socketRequest = new SocketRequest("update_model", Model.class);
        socketRequest.setParams(new Model(robot.getBrand(), robot.getModel(), robot.getDisplayId(), robot.getVersionAndroid(), robot.getBoard(), robot.getOsApi()));
        ChannelHandlerContext ctx = NettyChannelhandlerContextMap.get(oldRobot.getSimCode());
        if (null != ctx) {
            ctx.writeAndFlush(socketRequest.toString());
        } else {
            return true;
        }
        return false;
    }

    @RequestMapping(value = "/toUpdateWifi", method = RequestMethod.GET)
    public String toUpdateWifi(String simCode, ModelMap modelMap) {
        modelMap.put("simCode", simCode);
        return "robot/update_wifi";
    }

    @RequestMapping(value = "/wifi/getListByPage", method = RequestMethod.GET)
    @ResponseBody
    public Page<Wifi> getWifiAll(MongoPageRequest<Wifi> mongoPageRequest, Wifi wifi) {
        mongoPageRequest.setParams(wifi);
        return wifiRepository.getListByPage(mongoPageRequest);
    }

}